somaxconn、 tcp_max_syn_backlog 和 tcp_backlog 对 redis 性能的影响
最近我们的 api 经常会在高峰期出现下面的两个错误,两个错误都是在连接 redis 的时候出现的(连接 redis 使用的类库是 CSRedisCore
)。
异常1:
Connection was not opened
异常2:
【10.0.0.8:6379/0】状态不可用,等待后台检查程序恢复方可使用。Connect to server timeout
高峰期 redis 的 instantaneous_ops_per_sec
大概可以达到 300,000 左右; 而 connected_clients
大概可以达到 2,000 左右。
经过一段时间的排查,始终没有什么头绪。经过各种优化之后有所缓解,但始终无法根治。后来开始怀疑是 redis 的配置有关,于是开始逐项排查。
一、 排查可疑配置项
可疑配置项一
# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511
可疑配置项二
docker run --sysctl net.core.somaxconn=1024
我们的 redis 是运行在 docker 容器中的
tcp-backlog, 默认值为 511。按照 redis.conf 的注释来看,在高访问量的环境下,需要适当的调大这个值。且此值与系统内核的 somaxconn
和 tcp_max_syn_backlog
配置有关。
那么,somaxconn
和 tcp_max_syn_backlog
分别代表什么意思呢?
linux 会维护两个队列,未连接队列
和 已连接队列
,一个TCP连接首先会进入未连接队列
,在完成3次握手成功之后则会进入已连接队列
。而应用程序会从已连接队列
中取出连接,并进行响应。
所以,上述 redis.conf 配置文件中的 tcp-backlog
配置,实际上是对已连接队列的大小限制。
而 未连接队列
和 已连接队列
,在系统内核中又对应着 /etc/sysctl.conf
中的两个配置项:
未连接队列(TCP层)
- 对应配置:net.ipv4.tcp_max_syn_backlog
Ubuntu 18.04 下默认值为 256
# 查看 tcp_max_syn_backlog cat /proc/sys/net/ipv4/tcp_max_syn_backlog
已连接队列(应用层)
- 对应配置:net.core.somaxconn
Ubuntu 18.04 下默认值为 128
# 查看 somaxconn cat /proc/sys/net/core/somaxconn
综上所述:
- 如果应用程序处理不及时,则会导致已连接队列(somaxconn)堆积。
- 若已连接队列已满,会造成连接在3次握手完成后仍然无法进入已连接队列,最终导致未连接队列也被占满。
- 如果未连接队列(tcp_max_syn_backlog)已满,则新连接将一直处于等待ACK的状态,最终导致超时。
- redis.conf 的 tcp-backlog 配置 和 内核的 somaxconn 配置 如果不相同,则实际效果为两者中的较小值。
二、 修改内核配置 tcp_max_syn_backlog 与 somaxconn
要修改这两个值,并永久生效,我们可以直接将配置项加入到 /etc/sysctl.conf
文件:
# file: /etc/sysctl.conf
net.ipv4.tcp_max_syn_backlog = 4096
net.core.somaxconn = 4096
然后执行一下命令,使修改生效:
sudo sysctl -p
三、 修改 redis 配置 tcp-backlog
# file: redis.conf
# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 4096
四、 修改 docker run 参数,并使用新的配置重新创建 docker 容器
docker run --sysctl net.core.somaxconn=4096 --sysctl net.ipv4.tcp_max_syn_backlog=4096